package ui;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.geom.AffineTransform;

import gauge.DialGauge3State;

import javax.swing.JComponent;
import javax.swing.plaf.ComponentUI;

import model.Bounded3StateRangeModel;

public class BasicDialGaugeUI extends Gauge3StateUI 
{
	private Color textColor = Color.black;
	private Color bgColor = Color.lightGray;
	
	// needle_center is the center of rotation of the needle image

	private final int NEEDLE_CENTER = 21;
	
	protected DialGauge3State dialGauge;
	
	
	
	
	public BasicDialGaugeUI()
	{
		
	}
	
	public static ComponentUI createUI(JComponent x) {
        return new BasicDialGaugeUI();
    }

	
	
    public void installUI(JComponent c) {
    	
        dialGauge = (DialGauge3State)c;
       // installDefaults();
       // installListeners();
    }

    public void uninstallUI(JComponent c) {
        //uninstallDefaults();
        //uninstallListeners();
        dialGauge = null;
    }
    
    
    
/* TODO
 * The progressbar has methods associated with baseline and sizing.  These may be required by
 * the swing model.  If not, it'd be a good idea to implement them anyway.
 */

    
    public void drawZones(Graphics g, Bounded3StateRangeModel model)
    {

    	if(dialGauge.getZoneArcThickness() >0)
		{
			Graphics2D g2d = (Graphics2D)g;
			// calculate degrees per unit here for less clutter where its used
			double degreesPerUnit = model.getDegreeRange() / (model.getMax() - model.getMin());
			g2d.setStroke(new BasicStroke(dialGauge.getZoneArcThickness(), BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
			int x1= getWidth() /2;
			int y1 = getHeight()/2;
			
			// these values need to prepresent degrees, not values
			double lowerDangerStart = model.getDegreeOffset();								 
			double lowerDangerLength = (model.getLowerCautionTripPoint() - model.getMin()) * degreesPerUnit;  
			
			double lowerCautionStart = lowerDangerStart - lowerDangerLength; 
			double lowerCautionLength = (model.getSafeTripPoint() - model.getLowerCautionTripPoint()) * degreesPerUnit;
			
			double safeStart = lowerCautionStart - lowerCautionLength;
			double safeLength = (model.getUpperCautionTripPoint() - model.getSafeTripPoint()) * degreesPerUnit;
			
			double upperCautionStart = safeStart - safeLength;
			double upperCautionLength = (model.getUpperDangerTripPoint() - model.getUpperCautionTripPoint()) * degreesPerUnit;
			
			double upperDangerStart = upperCautionStart - upperCautionLength;
			double upperDangerLength = (model.getMax() - model.getUpperDangerTripPoint()) * degreesPerUnit;

			g2d.setColor(Color.red);
			g2d.drawArc(x1-dialGauge.getArcDistance(),y1-dialGauge.getArcDistance(), dialGauge.getArcWidth(), dialGauge.getArcHeight(),(int)lowerDangerStart,-(int)lowerDangerLength);

			g2d.setColor(Color.yellow);
			g2d.drawArc(x1-dialGauge.getArcDistance(),y1-dialGauge.getArcDistance(), dialGauge.getArcWidth(), dialGauge.getArcHeight(),(int)lowerCautionStart,-(int)lowerCautionLength);

			g2d.setColor(Color.green);
			g2d.drawArc(x1-dialGauge.getArcDistance(),y1-dialGauge.getArcDistance(), dialGauge.getArcWidth(), dialGauge.getArcHeight(),(int)safeStart,-(int)safeLength);
			
			g2d.setColor(Color.yellow);
			g2d.drawArc(x1-dialGauge.getArcDistance(),y1-dialGauge.getArcDistance(), dialGauge.getArcWidth(), dialGauge.getArcHeight(),(int)upperCautionStart,-(int)upperCautionLength);

			g2d.setColor(Color.red);
			g2d.drawArc(x1-dialGauge.getArcDistance(),y1-dialGauge.getArcDistance(), dialGauge.getArcWidth(), dialGauge.getArcHeight(),(int)upperDangerStart,-(int)upperDangerLength);
		}
    	
    }
    public void drawMinorTickMarks(Graphics g, Bounded3StateRangeModel model)
    {
    	
    	Graphics2D g2d = (Graphics2D)g;
    	g2d.setStroke(new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
		int x1= getWidth() /2;
		int y1 = getHeight()/2;
		int distance = dialGauge.getTickDistance() + dialGauge.getMinorTickLength();
		int tickLength = dialGauge.getMinorTickLength();
		double degreeRange = model.getDegreeRange();
		double min = model.getMin();
		double max = model.getMax();
		double degreesPerUnit = degreeRange / (max-min);
		double minorStepDegrees = dialGauge.getMinorTickSpacing() * degreesPerUnit;
		double offset = dialGauge.getModel().getDegreeOffset();

		
		for(double i=0;i<=degreeRange;i += minorStepDegrees)
		{
		g2d.setColor(textColor);
		g2d.drawLine((int) (x1+(distance-tickLength)*Math.cos(Math.toRadians(-offset + i))),
				(int) (y1+(distance-tickLength)*Math.sin(Math.toRadians(-offset + i))), 
				(int) (x1+distance*Math.cos(Math.toRadians(-offset+i))),
				(int) (y1+distance*Math.sin(Math.toRadians(-offset+i))));
		}
    }
    public void drawMajorTickMarks(Graphics g, Bounded3StateRangeModel model)
    {
  	
    	Graphics2D g2d = (Graphics2D)g;
		g2d.setStroke(new BasicStroke(2f));
		int x1= getWidth() /2;
		int y1 = getHeight()/2;
		// Set these as fields in the gauge.
		int distance = dialGauge.getTickDistance() + dialGauge.getMajorTickLength(); // how far out from center to draw (outter edge of circle)
		int tickLength=dialGauge.getMajorTickLength(); // length of tickmarks
		double degreeRange = model.getDegreeRange();
		double min = model.getMin();
		double max = model.getMax();
		double degreesPerUnit = degreeRange / (max-min);
		double majorStepDegrees = dialGauge.getMajorTickSpacing() * degreesPerUnit;
		double offset = dialGauge.getModel().getDegreeOffset();
		
		for(double i=0;i<=degreeRange;i += majorStepDegrees)
		{
			g2d.setColor(textColor);
			g2d.drawLine((int) (x1+(distance-tickLength)*Math.cos(Math.toRadians(-offset + i))),
				(int) (y1+(distance-tickLength)*Math.sin(Math.toRadians(-offset + i))), 
				(int) (x1+distance*Math.cos(Math.toRadians(-offset+i))),
				(int) (y1+distance*Math.sin(Math.toRadians(-offset+i))));
		} 
    }
    public void drawLabels(Graphics g, Bounded3StateRangeModel model)
    {
    	Graphics2D g2d = (Graphics2D)g;
		Font font = new Font("Arial", Font.ITALIC, 25);
		g2d.setFont(font);
		
		int x1= getWidth() /2;
		int y1 = getHeight()/2;
		int distance = dialGauge.getLabelDistance();
		//double angle = 45;
		int count=0;
		
		double min = model.getMin();
		double max = model.getMax();
		double degreeRange = model.getDegreeRange();
		double degreesPerUnit = degreeRange / (max-min);
		double offset = dialGauge.getModel().getDegreeOffset();
		
		for(double i=min;i<=max;i += dialGauge.getMajorTickSpacing())
		{
		
		g2d.setColor(textColor);
		String s = Integer.toString((int)i);
		int startXPos = (int) g2d.getFontMetrics().getStringBounds(s, g2d).getWidth();
		int startYPos = (int) g2d.getFontMetrics().getStringBounds(s, g2d).getHeight();
		g2d.drawString(s, 
				(int) (x1+distance*Math.cos(Math.toRadians(-offset+count*degreesPerUnit))-startXPos/2), 
				(int)(y1+distance*Math.sin(Math.toRadians(-offset+count*degreesPerUnit))+startYPos/2));
		count += dialGauge.getMajorTickSpacing();
		}
    }
    
    // The paint call looks funny
    public void paint(Graphics g, JComponent c) 
    {
    	Graphics2D g2d = (Graphics2D)g;
    	// can make smaller gauges like this:
    	//g2d.scale(.5,.5);
    	Image currentBG=null;
    	Bounded3StateRangeModel model = dialGauge.getModel(); //so I don't have to call getModel each time
		double value = model.getValue();
		double offset = model.getDegreeOffset();
		double min = model.getMin();
		double max = model.getMax();
		double degreesPerUnit = model.getDegreeRange() /(max-min);
		double angle=(value-min)*degreesPerUnit;
/*		
		System.out.println("value = " + value);
		System.out.println("offset = " + offset);
		System.out.println("Min = " + min);
		System.out.println("Max = " + max);
		System.out.println("degreeRange = " + model.getDegreeRange());
		System.out.println("degreesPerUnit = " + degreesPerUnit);
*/		
		AffineTransform bgTransform = new AffineTransform();
		AffineTransform transform = new AffineTransform();
		
		// set the background to white
		g2d.setColor(bgColor);
		g2d.fillRect(0,0,getWidth(), getHeight());
		
		//select the background image based on threshold values and currentValue
		if (value < model.getLowerCautionTripPoint())
			currentBG = dialGauge.getBackground_danger();
		else if (value >= model.getLowerCautionTripPoint() && value < model.getSafeTripPoint())
			currentBG = dialGauge.getBackground_caution();
		else if (value >=model.getSafeTripPoint() && value < model.getUpperCautionTripPoint())
			currentBG = dialGauge.getBackground_safe();
		else if (value >= model.getUpperCautionTripPoint() && value < model.getUpperDangerTripPoint())
			currentBG = dialGauge.getBackground_caution();
		else if(value >= model.getUpperDangerTripPoint())
			currentBG = dialGauge.getBackground_danger();
/*
 * newTransform.concatenate(AffineTransform.getTranslateInstance(x1, x2));
newTransform.concatenate(AffineTransform.getRotateInstance(Math.toRadians(rotationAngle), (double)iconW/2.0d, (double)iconH/2.0d));
newTransform.concatenate(AffineTransform.getScaleInstance((double)newW/(double)iconW, (double)newH/(double)iconH));

 */
		//position and draw background image
		
		bgTransform.setToTranslation((getWidth()/2 - currentBG.getWidth(dialGauge)/2),( getHeight()/2 - currentBG.getHeight(dialGauge)/2));
		
		g2d.drawImage(currentBG,bgTransform,null);
	
		if(dialGauge.isDrawZoneLines() == true)
			drawZones(g, model);
		if(dialGauge.isDrawMinorTickMarks()==true)
			drawMinorTickMarks(g, model);
		if(dialGauge.isDrawMajorTickMarks() == true)
			drawMajorTickMarks(g, model);
		if(dialGauge.isDrawLabels() == true)
			drawLabels(g, model);

		//position and rotate needle
		transform.setToTranslation(getWidth()/2 -NEEDLE_CENTER , getHeight()/2 -NEEDLE_CENTER);
		transform.rotate(Math.toRadians((double)(-offset + angle)), NEEDLE_CENTER,NEEDLE_CENTER);
		
		g2d.drawImage(dialGauge.getNeedleImage(),  transform, dialGauge);
    }

	public int getWidth() {
		return dialGauge.getWidth();
	}
/*
	public void setWidth(int width) {
		this.width = width;
	}
*/
	public int getHeight() {
		return dialGauge.getHeight();
	}
/*
	public void setHeight(int height) {
		this.height = height;
	}
  */  
}
